package com.project.ssmfo.common;

import java.io.IOException;
import java.net.URLDecoder;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.log4j.Logger;
import org.apache.shiro.web.servlet.OncePerRequestFilter;

import com.project.utils.AESUtil;
import com.project.utils.StringUtil;


public class DescryFilter extends OncePerRequestFilter{
	
	private static Logger logger = Logger.getLogger(DescryFilter.class);

	@Override
	  protected void doFilterInternal(ServletRequest srequest, 
	      ServletResponse sresponse, FilterChain filterChain) 
	      throws ServletException, IOException { 
		
		HttpServletRequest request=(HttpServletRequest) srequest;
		HttpServletResponse response=(HttpServletResponse) sresponse;
		
	    // 不过滤的uri 
	    String[] notFilter = new String[] { "login.html", "index.html" }; 
	  
	    // 请求的uri 
	    String uri = request.getRequestURI(); 
	  
	    // uri中包含background时才进行过滤 
	    if (uri.indexOf("/WEB-INF/") == -1 || uri.indexOf("/static/") == -1 || 
	    		uri.indexOf(".jsp") == -1 || uri.indexOf(".html")== -1 || 
	    				uri.indexOf("/sys/log") == -1||uri.indexOf(".js") == -1 || uri.indexOf(".css") == -1) { 
	      // 是否过滤 
	      boolean doFilter = true; 
	      for (String s : notFilter) { 
	        if (uri.indexOf(s) != -1) { 
	          // 如果uri中包含不过滤的uri，则不进行过滤 
	          doFilter = false; 
	          break; 
	        } 
	      } 
	      if (doFilter) { 
	    	  Map<String,String> treeMap = new TreeMap<String, String>();
	    	  if(request.getParameter("data_v4")!=null) {//AES方式
		    		treeMap.put("decrypt", "001");
		  			String data_v4=request.getParameter("data_v4");
		  			String key="";
		  			Map<String,String> map = getFinalAccessToken(request.getHeader("CLIENT-CSRF-TOKEN"));
					try {
						treeMap.put("decrypt", map.get("code"));
						treeMap.put("csrf_token", map.get("csrf_token"));
						if(map!=null&&map.get("code").equals("000")&&StringUtil.isNotEmpty(map.get("key"))) {//
							key=map.get("key");
	  						String data=AESUtil.decryptHex(data_v4, key);
	  						//防止解析时，带%报错或者+号丢失
	  						data = data.replaceAll("%(?![0-9a-fA-F]{2})", "%25");
	  						data = data.replaceAll("\\+", "%2B");
	  						data=URLDecoder.decode(data, "UTF-8");
	  						if(data!=null) {
	  							logger.info("after AES decrypt:"+data);
	  							String[] arrSplit=data.split("&");
	  							for(String strSplit:arrSplit){
							          String[] arrSplitEqual=null;         
							          arrSplitEqual= strSplit.split("=");
							          //解析出键值
							          if(arrSplitEqual.length>1)
							          {
							        	  treeMap.put(arrSplitEqual[0], arrSplitEqual[1]);
							          }
	  							 }
	  							treeMap.put("decrypt", "000");
	  						}
						}
						request = new DecryptHttpRequestWrapper(request,treeMap);
					} catch (Exception e) {
						e.printStackTrace();
					}
		  		} 
	     
	    }  
	       
	    } 
	 // 如果uri中不包含background，则继续 
	      filterChain.doFilter(request, response);
	  }
	
	
	/**
	 * 获取服务端秘钥
	 * 
	 * client_csrf_token,生成规则为csrf_token-随机6位字符串-sywybs倒叙-时间戳，
	 * 中间用短横线-分隔，然后上行请求参数中csrf_token和sjwybs不在传递，
	 * 其中随机6位字符串中最后一位必须为数字，
	 * 用于区分服务器端秘钥使用固定还是用户的token，偶数使用固定的秘钥，奇数使用用户的token
	 * @param client_csrf_token
	 * @return
	 */
	public static Map<String,String> getFinalAccessToken(String client_csrf_token){
		Map<String,String> map = new HashMap<String, String>();
		String code = "001";//解析失败
		String fixed_key = "";
		String client_token = "";
		String access_token = "";
		String final_key = "";
		String csrf_token = "";
		if(StringUtil.isNotEmpty(client_csrf_token)){
			try {
				String[] arr = client_csrf_token.split("&");
				if(arr.length==4){
					code = "000";
					String client=arr[0].substring(0, arr[0].indexOf("_"));
					client_token=arr[0].substring(arr[0].indexOf("_")+1,arr[0].length());
					if("h5v4".equals(client)) {
						fixed_key=Configuration.get("request_fixed_key_h5");
					}else if("andriodv4".equals(client)){
						fixed_key=Configuration.get("request_fixed_key_android");
					}else if("iosv4".equals(client)) {
						fixed_key=Configuration.get("request_fixed_key_ios");
					}else if("serverv2".equals(client)) {
						fixed_key=Configuration.get("request_fixed_key_server");
					}
					
					if("h5v4".equals(client)) {
						access_token=Configuration.get("access_token_h5");
					}else if("andriodv4".equals(client)){
						access_token=Configuration.get("access_token_android");
					}else if("iosv4".equals(client)) {
						access_token=Configuration.get("access_token_ios");
					}else if("serverv2".equals(client)) {
						access_token=Configuration.get("access_token_server");
					}
					
					csrf_token = arr[0];
				}
				if(code.equals("000")){
					final_key = combineKey(client_token, fixed_key, access_token);
				}
				
			} catch (Exception e) {
				e.printStackTrace();
				code = "001";//解析失败
			}		
		}
		map.put("csrf_token", csrf_token);
		map.put("key", final_key);
		map.put("code", code);
		return map;
	}

    
	/**
	 * <p>Title: combineKey</p>
	 * <p>Description: 按规则组合key</p>
	 * @param csrf_token
	 * @param fixed_key
	 * @param access_key
	 * @return String
	 */
	public static String combineKey(String csrf_token,String fixed_key,String access_key) {
		return getAfterRuleStr(csrf_token)+reverse(fixed_key)+afterServerRuleStr(access_key);
	}
	
	/**
	 * 按混淆规则对客户端秘钥进行重新组合
	 */
	public static String getAfterRuleStr(String val) {
		val=val.trim();
		String regEx="[^0-9]";   
		Pattern p = Pattern.compile(regEx);   
		Matcher m = p.matcher(val);
		String number=m.replaceAll("").trim();
		String numberSort="";
		int max=0;
		int minodd=9;
		int mineven=8;
		int index1=Integer.valueOf(number.substring(0, 1));
		int index6=Integer.valueOf(number.substring(5, 6));
		for (int i = 0; i <number.length(); i++)
        {
            numberSort = number.substring(i, i+1) + numberSort;
            Integer a=Integer.valueOf(number.substring(i, i+1));
            if(max<a) max=a;
            if(a%2>0) {
            	if(minodd>a) minodd=a;
            }else {
            	if(mineven>a) mineven=a;
            }	
            
        }
		int rand=((index1+index6)*max)%mineven+minodd;
		val="";
		for(int i = 0; i <numberSort.length(); i++){
			int b= Integer.valueOf(numberSort.substring(i, i+1))*rand;
			if(b<10) {
				val=b+"0" + val;
			}else {
				val=b%10+""+b/10 + val;
			}
		}
		return val;
	}
	
	/**
	 * <p>Title: reverse</p>
	 * <p>Description: 颠倒字符串顺序</p>
	 * @param val
	 * @return String
	 */
	public static String reverse(String val) {
		String numberSort="";
		for (int i = 0; i <val.length(); i++)
        {
            numberSort = val.substring(i, i+1) + numberSort;
        }
		val=numberSort;
		return val;
		
	}
	
	/**
	 * 按混淆规则对服务器端秘钥进行重新组合
	 */
	public static String afterServerRuleStr(String val) {
		String str1=val.substring(4, 8);
		String str2=val.substring(0, 4);
		 char[] ch = str1.toCharArray();  
	     StringBuffer sbf = new StringBuffer();
	     for(int i=0; i< 4; i++){  
	           sbf.append(charToUpperCase(ch[i]));  
	      }
	     sbf.append(str2);
	     val=sbf.substring(0,2)+ sbf.substring(4,6)+sbf.substring(2,4)+ sbf.substring(6,8);
		return val;
	}
	
	
	/**转大写**/  
    public static char charToUpperCase(char ch){  
        if(ch <= 122 && ch >= 97){  
            ch -= 32;  
        }  
        return ch;  
    }  
    /***转小写**/  
    public char charToLowerCase(char ch){  
        if(ch <= 90 && ch >= 65){  
            ch += 32;  
        }  
        return ch;  
    }
	 
}
